package xj.model.uml;

import static xj.model.uml.UMLModelConstants.ATTR_TEXT;
import static xj.model.uml.UMLModelConstants.ATTR_COMMENT;
import static xj.model.uml.UMLModelConstants.ATTR_CONSTRAINT;
import static xj.model.uml.UMLModelConstants.ROLE_COMMENT;
import static xj.model.uml.UMLModelConstants.ROLE_CONSTRAINT;
import static xj.model.uml.UMLModelConstants.ROLE_NOTE;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import xj.meta.AbstractModelElement;

public abstract class BasicModelElement 
  extends AbstractModelElement {

  @Override
  public Object clone() 
    throws CloneNotSupportedException {
    BasicModelElement be = (BasicModelElement) super.clone();
    be.notes = new HashSet<Note>();
    Iterator<Note> iter1 = notes.iterator();
    while (iter1.hasNext()) {
      Note n = iter1.next();
      be.addNote((Note) n.clone());
    }

    be.constraints = new HashSet<Constraint>();
    Iterator<Constraint> iter2 = constraints.iterator();
    while (iter2.hasNext()) {
      Constraint c = iter2.next();
      be.addConstraint((Constraint) c.clone());
    }

    be.comments = new HashSet<Comment>();
    Iterator<Comment> iter3 = comments.iterator();
    while (iter3.hasNext()) {
      Comment c = iter3.next();
      be.addComment((Comment) c.clone());
    }

    return be;
  }

  public Set<Constraint> getConstraints() {
    return constraints;
  }

  public Set<String> getConstraintNames() {
    Set<String> result = new HashSet<String>();
    if (constraints != null) {
      Iterator<Constraint> iter = constraints.iterator();
      while (iter.hasNext()) {
	Constraint c = iter.next();
	String name = c.getName();
	if (name == null) {
	  name = "";
	} else {
	  name = name.trim();
	}
	result.add(name);
      }
    }
    return result;
  }

  public void addConstraint(Constraint constraint) {
    if (constraint != null) {
      constraints.add(constraint);
      addOwnedElement(constraint, ROLE_CONSTRAINT);
    }
  }

  public void removeConstraint(Constraint constraint) {
    if (constraint != null) {
      constraints.remove(constraint);
      removeOwnedElement(constraint);
    }
  }

  public void removeConstraint(String name) {
    if (constraints != null) {
      if (name == null) {
	name = "";
      } else {
	name = name.trim();
      }
      Iterator<Constraint> iter = constraints.iterator();
      while (iter.hasNext()) {
	Constraint c = iter.next();
	String cname = c.getName();
	if (name.equals(cname)) {
	  iter.remove();
	  removeOwnedElement(c);
	}
      }
    }
  }

  public void setConstraint(String s) {
    setConstraint(null, null, s);
  }

  public void setConstraint(String name, String lang, String body) {
    if (name == null) {
      name = "";
    } else {
      name = name.trim();
    }
    Constraint c = getConstraint(name);
    if (c != null) {
      c.setLang(lang);
      c.setBody(body);
    } else {
      addConstraint(new Constraint(name, lang, body));
    }
  }

  public String getConstraintBody() {
    Constraint cons = getConstraint();
    if (cons != null) {
      return cons.getBody();
    }
    return null;
  }

  // return the first constraint
  public Constraint getConstraint() {
    if (constraints != null) {
      Iterator<Constraint> iter = constraints.iterator();
      if (iter.hasNext()) {
	return iter.next();
      }
    }
    return null;
  }

  public Constraint getConstraint(String name) {
    if (constraints != null) {
      if (name == null) {
	name = "";
      } else {
	name = name.trim();
      }

      Iterator<Constraint> iter = constraints.iterator();
      while (iter.hasNext()) {
	Constraint c = iter.next();
	String cname = c.getName();
	if (name.equals(cname)) {
	  return c;
	}
      }
    }
    return null;
  }

  public Set<Comment> getComments() {
    return comments;
  }

  public void addComment(Comment comment) {
    if (comment != null) {
      comments.add(comment);
      addOwnedElement(comment, ROLE_COMMENT);
    }
  }

  public void removeComment(Comment comment) {
    if (comment != null) {
      comments.remove(comment);
      removeOwnedElement(comment);
    }
  }

  public void setComment(String s) {
    Comment c = getComment();
    if (c != null) {
      c.setText(s);
    } else {
      addComment(new Comment(s));
    }
  }

  public void setComment(String type, String text) {
    Comment c = getComment();
    if (c != null) {
      c.setType(type);
      c.setText(text);
    } else {
      addComment(new Comment(type, text));
    }
  }

  public String getCommentText() {
    Comment c = getComment();
    if (c != null) {
      return c.getText();
    }
    return null;
  }

  // return the first comment
  public Comment getComment() {
    if (comments != null) {
      Iterator<Comment> iter = comments.iterator();
      if (iter.hasNext()) {
	return iter.next();
      }
    }
    return null;
  }

  public Set<Note> getNotes() {
    return notes;
  }

  public void addNote(Note note) {
    if (note != null) {
      notes.add(note);
      addOwnedElement(note, ROLE_NOTE);
    }
  }

  public void removeNote(Note note) {
    if (note != null) {
      notes.remove(note);
      removeOwnedElement(note);
    }
  }

  @Override
  public void deconstruct() {
    super.deconstruct();
    notes.clear();
  }

  @Override
  protected boolean asElement(String attrName) {
    if (attrName != null) {
      return (attrName.equals(ATTR_TEXT) || 
	      attrName.equals(ATTR_COMMENT) || 
	      attrName.equals(ATTR_CONSTRAINT));
    }
    return false;
  }

  @Override
  protected boolean inCDATASection(String name) {
    return asElement(name);
  }

  protected BasicModelElement() {
  }

  protected Set<Constraint> constraints = new HashSet<Constraint>();

  protected Set<Comment> comments = new HashSet<Comment>();

  protected Set<Note> notes = new HashSet<Note>();

}
